import logging
from datetime import timedelta
from typing import Any

from aiogram import types
from aiogram_dialog import DialogManager, StartMode
from fluentogram import TranslatorRunner

from src.bot.services.tg_helpers import answer_msg_with_autodelete
from src.bot.states import ClientSG, PaymentSG
from src.core.models.enums import Currency, SubscriptionType
from src.core.payment_client.client import FondyPaymentClient
from src.core.utils.strings import generate_digits_string
from src.database import services

logger = logging.getLogger(__name__)


async def select_payment_method(
    call: types.CallbackQuery, widget: Any, manager: DialogManager
):
    locale: TranslatorRunner = manager.middleware_data.get("locale")
    fondy: FondyPaymentClient = manager.middleware_data.get("fondy")
    bot_settings_service: services.BotSettingsService = manager.middleware_data.get(
        "bot_settings_service"
    )
    subscription_service: services.SubscriptionService = manager.middleware_data.get(
        "subscription_service"
    )
    bill_service: services.BillService = manager.middleware_data.get("bill_service")

    manager.dialog_data["payment_method"] = widget.widget_id
    if widget.widget_id == "activation_code":
        await manager.switch_to(PaymentSG.enter_activation_code)
    else:
        subscription_type: str = manager.dialog_data.get("subscription_type")
        user_subscription = await subscription_service.get_active_user_subscription(
            call.from_user.id
        )
        if user_subscription:
            subscription_type = user_subscription.type.name

        bot_settings = await bot_settings_service.get_bot_settings()
        user_lang = locale.translators[0].locale
        currency = getattr(Currency, user_lang)
        order_sum = getattr(bot_settings, f"price_{subscription_type}_{user_lang}")
        bill = await bill_service.create_bill(order_sum, currency, call.from_user.id)
        order_id = f"bot_payment_{bill.id}_{generate_digits_string(4)}"
        invoice = await fondy.create_bill(
            order_sum * 10,
            order_id,
            currency_in=currency.value,
            language=user_lang,
            order_description=locale.get(
                "subscription-payment", tariff_name=locale.get(subscription_type)
            ),
        )
        logger.info(invoice)
        invoice = invoice.get("response")
        invoice_id = invoice.get("payment_id")
        await bill_service.update_bill_invoice_id(bill.id, invoice_id)

        logger.info(
            f"В кассе создан новый счет №{invoice_id} на сумму {order_sum} {currency}"
        )
        manager.dialog_data["order_id"] = order_id
        manager.dialog_data["bill_link"] = invoice.get("checkout_url")
        manager.dialog_data["payment_sum"] = order_sum

        await manager.next()


async def validate_activation_code(
    message: types.Message,
    _,
    manager: DialogManager,
    activation_code: str,
):
    locale: TranslatorRunner = manager.middleware_data.get("locale")
    codes_service: services.ActivationCodeService = manager.middleware_data.get(
        "codes_service"
    )
    subscription_service: services.SubscriptionService = manager.middleware_data.get(
        "subscription_service"
    )

    subscription_type = manager.dialog_data.get("subscription_type")
    user_subscription = await subscription_service.get_active_user_subscription(
        message.from_user.id
    )
    if user_subscription:
        subscription_type = user_subscription.type
    else:
        subscription_type = getattr(SubscriptionType, subscription_type)

    activation_code = await codes_service.get_activation_code_by_name(
        activation_code, subscription_type
    )

    if not activation_code:
        await message.answer(locale.get("wrong-code"))
        return

    if activation_code.uses_number >= activation_code.limit != 0:
        await answer_msg_with_autodelete(
            message, locale.get("code-usage-limit-reached")
        )
        return

    if (
        await subscription_service.get_subscription_with_activation_code(
            message.from_user.id, activation_code.id
        )
        and not activation_code.reusable
    ):
        # Запрещаем одному и тому же юзеру использовать один промо в разных заказах
        await answer_msg_with_autodelete(message, locale.get("code-already-used"))
        return

    await codes_service.increase_activation_code_uses(activation_code.id)

    if user_subscription:
        new_date = user_subscription.end_date + timedelta(days=31)
        await subscription_service.extend_subscription(user_subscription.id, new_date)
        # TODO Добавлять код активации пользователю
        await message.answer(locale.get("subscription-extended", end_date=new_date))
        await manager.done()
    else:
        subscription = await subscription_service.create_subscription(
            message.from_user.id, subscription_type, activation_code.id
        )
        await message.answer(
            locale.get("subscription-created", end_date=subscription.end_date)
        )
        await manager.start(ClientSG.start, mode=StartMode.RESET_STACK)


async def check_payment(call: types.CallbackQuery, _, manager: DialogManager):
    """Проверяем оплату подиски"""

    locale: TranslatorRunner = manager.middleware_data.get("locale")
    fondy: FondyPaymentClient = manager.middleware_data.get("fondy")
    subscription_service: services.SubscriptionService = manager.middleware_data.get(
        "subscription_service"
    )
    order_id: str = manager.dialog_data.get("order_id")

    order_status = await fondy.order_status(order_id)
    order_status = order_status["response"].get("order_status")

    if order_status in ["created", "processing"] or not order_status:
        await call.answer(locale.get("payment-waiting"))
        return
    elif order_status in ["declined", "expired"] or not order_status:
        await call.message.answer("payment-failed")
        return
    elif order_status == "approved":
        user_subscription = await subscription_service.get_active_user_subscription(
            call.from_user.id
        )
        if user_subscription:
            new_date = user_subscription.end_date + timedelta(days=31)
            await subscription_service.extend_subscription(
                user_subscription.id, new_date
            )
            await call.message.answer(
                locale.get("subscription-extended", end_date=new_date)
            )
            await manager.done()
        else:
            subscription = await subscription_service.create_subscription(
                call.from_user.id,
                getattr(SubscriptionType, manager.dialog_data.get("subscription_type")),
            )
            await call.message.answer(
                locale.get("subscription-created", end_date=subscription.end_date)
            )
            await manager.start(ClientSG.start, mode=StartMode.RESET_STACK)
